from .constant import EventType, OrderType, AssetType, CashFlowType, OffsetType
from dataclasses import dataclass,field
from datetime import datetime
from typing import Dict, Optional, List
from abc import ABC, abstractmethod
from pandas import DataFrame
import pandera as pa
import numpy as np
from pandera.typing import Series
from typing import Dict, Optional, List, Tuple
from datetime import datetime, timedelta
from loguru import logger
@dataclass
class BaseData(ABC):
    """"
    Any data object should inherit base data.
    """
    timestamp: datetime
    asset_type: AssetType
    symbol: str
@dataclass
class CashFlowData(BaseData):
    """现金流数据"""
    cashflow_type: CashFlowType
    amount: float  # 现金流金额
    related_position: Optional[str] = None  # 相关持仓的标识符
    
    def is_outflow(self) -> bool:
        """
        判断是否为现金流出
        
        对于债券：
        - 利息收入 (INTEREST/COUPON) 是流入
        - 到期本金 (PRINCIPAL) 是流入
        - 到期事件 (MATURITY) 不涉及现金流
        """
        # 所有的利息和本金都是现金流入
        if self.cashflow_type in [CashFlowType.INTEREST, 
                                CashFlowType.PRINCIPAL]:
            return False
        # 到期事件不涉及现金流
        elif self.cashflow_type == CashFlowType.MATURITY:
            return False
        # 其他情况默认为现金流出
        return True

    def _replace(self, **kwargs):
        """替换字段值并返回新的实例"""
        return CashFlowData(**{**self.__dict__, **kwargs})
@dataclass
class Asset(ABC):
    """资产基类"""
    symbol: str
    # asset_type: AssetType
    
    @abstractmethod
    def get_cashflows(self, start_date: datetime, end_date: datetime) -> List[CashFlowData]:
        """获取指定时间段内的现金流事件"""
        pass
    
    @abstractmethod
    def is_matured(self, current_date: datetime) -> bool:
        """判断资产是否到期"""
        pass
    
    @abstractmethod
    def accrued_interest(self, current_date: datetime, quantity: float) -> float:
        """计算应计利息"""
        return 0
    
    def calc_ytm(self, clean_price: float, value_date: datetime) -> float:
        """
        计算到期收益率（YTM）
        
        """
        pass



@dataclass
class OrderData(BaseData):
    """订单数据"""
    order_type: OrderType
    quantity: float
    price: Optional[float] = None  # 限价单时使用
    direction: int = 1  # 1 为做多，-1 为做空
    asset:Optional=None
    
    def calculate_total_cost(self) -> float:
        """计算订单总成本（包括手续费）"""
        
        if self.asset is not None:
            accured_interest = self.asset.accrued_interest(self.timestamp, self.quantity)
        else:
            accured_interest = 0
        
        if self.price is None:
            raise ValueError("Order price is not set")
        if self.asset_type == AssetType.REPO:
            # 回购直接使用quantity
            # 正回购：收到资金（正现金流）
            # 逆回购：付出资金（负现金流）
            base_cost = (self.quantity+accured_interest) * self.direction 
        else:
            base_cost = (accured_interest + self.quantity * self.price) * self.direction 
                        
        return base_cost

@dataclass
class TradeData(BaseData):
    """成交数据"""
    quantity: float
    price: float
    commission: float #手续费
    direction: int
    transaction_cost: float  # 其他交易成本（如印花税、过户费等）
    asset:Optional = None
    
    
    def calculate_total_cost(self) -> float:
        """
        计算总成本（现金占用）
        对于回购：
        - 正回购（direction < 0）：收到资金，现金流为正
        - 逆回购（direction > 0）：付出资金，现金流为负
        对于其他资产：
        - 买入（direction > 0）：付出资金，现金流为负
        - 卖出（direction < 0）：收到资金，现金流为正
        """
        if self.asset is not None:
            accured_interest = self.asset.accrued_interest(self.timestamp, self.quantity)
        else:
            accured_interest = 0
        if self.asset_type == AssetType.REPO:
            # 回购直接使用quantity
            # 正回购：收到资金（正现金流）
            # 逆回购：付出资金（负现金流）
            base_cost = (self.quantity+ accured_interest) * self.direction 
        else:
            base_cost = (self.quantity * self.price + accured_interest) * self.direction 
        total_cost = base_cost + self.commission + self.transaction_cost

        return total_cost



@dataclass
class BarData(BaseData):
    """K线行情数据"""
    open_price: float  # 开盘价
    high_price: float  # 最高价
    low_price: float  # 最低价
    close_price: float  # 收盘价
    volume: float  # 成交量
    avg_price: float  # 平均价
    open_interest: float  # 持仓量/开仓量
    offset:OffsetType # K线周期
    duration:Optional[float] = None # 久期
    YTM:Optional[float] = None # YTM
    
    def __post_init__(self):
        """数据初始化后的处理"""
        # 确保所有价格都是非负数
        for price_attr in ['open_price', 'high_price', 'low_price', 'close_price', 'avg_price']:
            price = getattr(self, price_attr)
            if price is not None and price < 0:
                raise ValueError(f"{price_attr} 不能为负值: {price}")
        
        # 确保成交量和持仓量为非负数
        for volume_attr in ['volume', 'open_interest']:
            volume = getattr(self, volume_attr)
            if volume is not None and volume < 0:
                raise ValueError(f"{volume_attr} 不能为负值: {volume}")
        
        # 确保最高价>=开盘价、收盘价>=最低价
        if self.high_price < self.open_price or self.high_price < self.close_price:
            raise ValueError(f"最高价 {self.high_price} 必须大于或等于开盘价 {self.open_price} 和收盘价 {self.close_price}")
        
        if self.low_price > self.open_price or self.low_price > self.close_price:
            raise ValueError(f"最低价 {self.low_price} 必须小于或等于开盘价 {self.open_price} 和收盘价 {self.close_price}")
@dataclass
class FactorData():
    """因子数据"""
    timestamp: datetime
    # 因子值字典{dataframe:index=标的代码，columns=['factor_name','factor_value']}
    factor_values: List[DataFrame]  
    




# 持仓类

@dataclass
class Position:
    """单个证券持仓类"""
    asset: Asset
    quantity: float = 0  # 对于回购，quantity 表示回购金额的绝对值
    avg_price: float = 0
    current_price: float = 0
    current_date: datetime = field(default_factory=datetime.now)
    trades: List[TradeData] = field(default_factory=list)
    cashflows: List[CashFlowData] = field(default_factory=list)
    first_trade_date: Optional[datetime] = None  # 首次建仓时间
    duration: Optional[float] = None
    YTM: Optional[float] = None
    @property
    def is_liability(self):
        return self.quantity < 0
    @property
    def symbol(self) -> str:
        return self.asset.symbol
    
    @property
    def asset_type(self) -> AssetType:
        return self.asset.asset_type
    
    @property
    def holding_period(self) -> int:
        """
        计算持仓周期（天数）
        如果没有建仓或者已清仓，返回0
        """
        if self.quantity == 0 or self.first_trade_date is None:
            return 0
        return (self.current_date - self.first_trade_date).days
    
    def update_on_trade(self, trade: TradeData) -> None:
        """
        更新持仓信息
        Args:
            trade: 成交事件
            
        对于回购：
        - 更新quantity，正数表示逆回购（资产），负数表示正回购（负债）
        
        对于其他资产：
        - 只有买入（direction > 0）会改变平均价格
        - 卖出不改变平均价格
        """
        old_quantity = self.quantity
        fill_data = trade
        if self.asset_type == AssetType.REPO:
            # 回购特殊处理
            
            self.quantity = fill_data.quantity * fill_data.direction
            self.avg_price = fill_data.price  # 回购利率
        else:
            # 其他资产正常处理
            # 考虑方向计算实际数量
            actual_quantity = fill_data.quantity * fill_data.direction
            
            # 只有买入才更新平均价格
            if fill_data.direction > 0:  # 买入
                old_cost = self.quantity * self.avg_price
                new_cost = fill_data.quantity * fill_data.price
                new_quantity = self.quantity + actual_quantity
                
                if new_quantity != 0:
                    self.avg_price = (old_cost + new_cost) / new_quantity
            
            # 更新持仓数量
            self.quantity = self.quantity + actual_quantity
        
        # 如果是首次建仓，记录时间
        if old_quantity == 0 and self.quantity != 0:
            self.first_trade_date = fill_data.timestamp
        # 如果清仓，重置首次建仓时间
        elif self.quantity == 0:
            self.first_trade_date = None
        
        # 记录交易
        self.trades.append(fill_data)
    
    def add_cashflow(self, cashflow: CashFlowData) -> None:
        """添加现金流记录"""
        self.cashflows.append(cashflow)
    
    def get_cashflows(self, start_date: datetime, end_date: datetime) -> List[CashFlowData]:
        """
        获取指定时间段内的现金流事件
        如果是负债，现金流方向需要取反
        """
        events = self.asset.get_cashflows(start_date, end_date)
        # 转换为实际持仓量对应的现金流
        events = [
            event._replace(amount=event.amount * self.quantity)
            for event in events
        ]
        
        # 如果是负债，现金流方向需要取反
        if self.is_liability:
            events = [
                event._replace(amount=-event.amount)
                for event in events
            ]
            
        return events
    
    
    def calculate_accrued_interest(self, current_date: datetime) -> float:
        """
        计算应计利息
        如果是负债，应计利息为负
        """
        interest = self.asset.accrued_interest(current_date, self.quantity)
        if self.is_liability:
            return -abs(interest)
        return interest
    
    def market_value(self) -> float:
        """
        计算市值
        
        对于回购：
        - 市值等于回购金额（quantity）
        
        对于其他资产：
        - 市值 = 数量 * 当前价格 + 应计利息
        """
        if self.asset_type == AssetType.REPO:
            # 回购的市值就是回购金额+应计利息
            clean_value = self.quantity
        else:
            # 其他资产需要加上应计利息
            clean_value = self.quantity * self.current_price  # 净价市值
        accrued_interest = self.asset.accrued_interest(self.current_date, self.quantity)
        return clean_value + accrued_interest
    
   

@dataclass
class PortfolioPosition:
    """投资组合持仓管理"""
    positions: Dict[str, Position] = field(default_factory=dict)
    initial_capital: float = 1000000.0
    current_cash: float = field(init=False)
    cashflow_history: List[CashFlowData] = field(default_factory=list)
    current_date: datetime = field(init=False)
    
    def __post_init__(self):
        self.current_cash = self.initial_capital
    
    def add_position(self, asset: Asset) -> None:
        """添加新的资产持仓"""
        if asset.symbol not in self.positions:
            self.positions[asset.symbol] = Position(asset=asset)
    
    def update_position_on_fill(self, trade: TradeData) -> None:
        """更新持仓"""
        symbol = trade.symbol
        if symbol not in self.positions:
            raise ValueError(f"Position for {symbol} does not exist")
        
        # 更新现金
        total_cost = trade.calculate_total_cost()

        self.current_cash -= total_cost

        
        # 更新持仓
        self.positions[symbol].update_on_trade(trade)
    def update_position_on_cashflow(self, cashflow_event: CashFlowData) -> None:
        """
        处理现金流事件
        对于负债，现金流的方向需要取反
        """
        # 获取相关持仓
        position = None
        if cashflow_event.related_position in self.positions:
            position = self.positions[cashflow_event.related_position]

        # 确定实际的现金流方向
        is_outflow = cashflow_event.is_outflow()
        
        if position and position.is_liability:
            is_outflow = not is_outflow  # 如果是负债到期，现金流方向取反
        
        # 更新现金
        if is_outflow:
            self.current_cash -= cashflow_event.amount
        else:
            self.current_cash += cashflow_event.amount

        if cashflow_event.cashflow_type == CashFlowType.MATURITY:
            if cashflow_event.related_position in self.positions:
                position = self.positions[cashflow_event.related_position]
                position.quantity = 0  # 清空持仓
        # 记录现金流事件
        self.cashflow_history.append(cashflow_event)
        
        # 如果现金流与特定持仓相关，更新持仓记录
        if position:
            position.add_cashflow(cashflow_event)
    
    def check_cashflows(self, current_date: datetime) -> List[CashFlowData]:
        """检查所有非0持仓的当日现金流事件"""
        cashflows = []
        for position in self.positions.values():
            if position.quantity == 0:
                # 如果不是持仓的品种，跳过，不需要记录现金流事件
                continue
            cashflows.extend(
                position.get_cashflows(current_date, current_date)
            )
        return cashflows
    
    def update_market_data(self, 
                            symbol: str, 
                            price: float, 
                            duration: float,
                            YTM: float,
                            current_date: datetime,
                            ) -> None:
        """更新市场价格和市场日期"""
        if symbol in self.positions:
            self.positions[symbol].current_price = price 
            self.positions[symbol].current_date = current_date
            self.positions[symbol].duration = duration if duration is not None else self.positions[symbol].duration
            self.positions[symbol].YTM = YTM if YTM is not None else self.positions[symbol].YTM
        

            
    def duration(self) -> float:
        """
        计算组合久期
        """
        return sum(
            pos.duration * pos.market_value() for pos in self.positions.values() 
            if pos.quantity != 0 and pos.duration is not None
        )/self.net_total_value()
    def YTM(self) -> float:
        """
        计算组合YTM
        """
        return sum(
            pos.YTM * pos.market_value() for pos in self.positions.values() 
            if pos.quantity != 0 and pos.duration is not None
        )/self.net_total_value()
        
    def gross_total_value(self) -> float:
        """
        计算组合总价值（不考虑负债）
        包括：
        1. 当前现金
        2. 所有资产的市值（不包括负债）
        """
        return max(self.current_cash,0) + sum(
            pos.market_value() for pos in self.positions.values() 
            if pos.quantity != 0 and not pos.is_liability 
        )
    
    def net_total_value(self) -> float:
        """
        计算组合净价值（考虑负债）
        包括：
        1. 当前现金
        2. 所有资产的市值
        3. 减去所有负债的市值
        """
        

        return self.current_cash + sum(
            pos.market_value() for pos in self.positions.values() if pos.quantity != 0
        ) 

    
    def get_position_sizes(self) -> Dict[str, float]:
        """获取所有持仓数量"""
        return {
            symbol: pos.quantity 
            for symbol, pos in self.positions.items() if pos.quantity != 0
        }
    
    def get_position_weights(self) -> Dict[str, float]:
        """计算持仓权重"""
        total = self.net_total_value() #净资产

        return {
            symbol: (pos.market_value() / total)
            for symbol, pos in self.positions.items() if pos.quantity != 0
        }
    def get_position_details(self) -> List[Position]:
        """
        获取所有持仓详情
        
        Returns:
            List[Position]: 所有持仓详情
        """
        return [
            pos
            for _, pos in self.positions.items() if pos.quantity != 0
        ]

@dataclass
class BacktestResultSchema(pa.DataFrameModel):
    """回测输出DataFrame结构
    Attributes:
        date: 日期
        total_value: 组合净值
        returns: 当日收益率
        cash: 账户可用现金
        positions: 持仓数量
        weights: 标的持仓权重
        accrued_interest:应计利息
        trades: 交易记录
        cashflows: 现金流记录
        position_detail: 持仓记录
        duration: 组合久期
        YTM: 组合YTM
    """
    date: Series[pa.DateTime] 
    total_value: Series[float] 
    returns: Series[float] 
    cash: Series[float] 
    positions: Series[Dict[str, float]]
    weights: Series[Dict[str,float]]
    accrued_interest: Series[float]  
    trades: Series[List[TradeData]]
    cashflows: Series[List[CashFlowData]]
    position_detail: Series[List[Position]]
    duration: Series[float]
    YTM: Series[float]


#资产类

@dataclass
class Bond(Asset):
    """债券类"""
    name:str=None
    secucategory:str = None #债券类别
    par_value: float = 100.0  # 面值
    issue_price: float = 100.0  # 发行价格，零息债券必须录入
    coupon_rate: Optional[float] = None  # 票面利率
    value_date: datetime = field(default_factory=datetime.now) #起息日
    maturity_date: datetime = field(default_factory=lambda: datetime.now() + timedelta(days=365))
    payment_frequency: int = 1  # 每年付息次数
    interest_basis: int = 365  # 计息基准，可选365或360
    explicit_cashflows: Optional[List[Tuple[datetime, float, CashFlowType]]] = None  # 明确的现金流列表，每项为(日期, 金额, 类型)
    bond_type:Optional[int] = None #附息：10 贴现：20 零息:30
    def __post_init__(self):
        """初始化后处理"""
        self.asset_type = AssetType.BOND
        
        # 验证计息基准
        if self.interest_basis not in [360, 365]:
            raise ValueError("计息基准必须为360或365")
        
        # 如果提供了明确的现金流，按日期排序
        if self.explicit_cashflows:
            self.explicit_cashflows.sort(key=lambda x: x[0])
    
    @property
    def is_zero_coupon(self) -> bool:
        """判断是否为零息债券"""
        return 1 if self.bond_type in (20,30) else 0
    
    @property
    def payment_dates(self) -> List[datetime]:
        """获取所有付息日期，包括到期日"""
        if self.explicit_cashflows:
            if self.is_zero_coupon:
                return [date for date, _, flow_type in self.explicit_cashflows 
                   if flow_type == CashFlowType.PRINCIPAL]
            else:
                return [date for date, _, flow_type in self.explicit_cashflows 
                   if flow_type == CashFlowType.INTEREST]
        
           

            
        # 计算付息日期
        dates = []
        days_between_payments = self.interest_basis // self.payment_frequency
        
        # 计算第一个付息日
        first_payment_date = self.value_date + timedelta(days=days_between_payments)
        
        # 如果第一个付息日超过到期日，则返回到期日
        if first_payment_date > self.maturity_date:
            return [self.maturity_date]
        # 计算总计的付息次数
        total_payments_number = round((self.maturity_date - self.value_date).days / days_between_payments)
        # 计算所有付息日
        current_date = first_payment_date
        while current_date < self.maturity_date:  
            dates.append(current_date)
            current_date += timedelta(days=days_between_payments)
 
        
        # 一年之内，付息次数必然与付息频率相等，最后一次付息一定是到期日
        if (not dates or dates[-1] != self.maturity_date):
            if len(dates) < total_payments_number:
                dates.append(self.maturity_date)
            else:
                dates[-1] = self.maturity_date
        return sorted(dates)

    def _get_payment_amount(self, payment_date: datetime) -> float:
        """获取付息金额"""
        if self.explicit_cashflows:
            for date, amount, flow_type in self.explicit_cashflows:
                if date == payment_date and flow_type == CashFlowType.INTEREST:
                    return amount
        return self.par_value * self.coupon_rate / self.payment_frequency

    def get_cashflows(self, start_date: datetime, end_date: datetime) -> List[CashFlowData]:
        """获取指定时间段内的现金流事件"""
        # 确保日期是datetime类型
        if isinstance(start_date, int):
            start_date = datetime.fromtimestamp(start_date)
        if isinstance(end_date, int):
            end_date = datetime.fromtimestamp(end_date)
        
        cashflows = []
        
        # 如果债券在此期间到期，添加到期事件（无论是否有明确现金流）
        if start_date <= self.maturity_date <= end_date:
            # 到期事件
            cashflows.append(
                CashFlowData(
                    timestamp=self.maturity_date,
                    asset_type=AssetType.BOND,
                    symbol=self.symbol,
                    amount=0,  # 到期事件不涉及实际现金流
                    cashflow_type=CashFlowType.MATURITY,
                    related_position=self.symbol
                )
            )
        
        # 如果有明确的现金流，直接使用
        if self.explicit_cashflows:
            for date, amount, flow_type in self.explicit_cashflows:
                if start_date <= date <= end_date:
                    cashflows.append(
                        CashFlowData(
                            timestamp=date,
                            asset_type=AssetType.BOND,
                            symbol=self.symbol,
                            amount=amount,
                            cashflow_type=flow_type,
                            related_position=self.symbol
                        )
                    )
            return sorted(cashflows, key=lambda x: x.timestamp)
        else:
        # 否则使用默认的现金流计算逻辑
        # 如果债券在此期间到期，添加本金还款（已经添加了到期事件）
            if start_date <= self.maturity_date <= end_date:
                # 本金还款
                cashflows.append(
                    CashFlowData(
                        timestamp=self.maturity_date,
                        asset_type=AssetType.BOND,
                        symbol=self.symbol,
                        amount=self.par_value,
                        cashflow_type=CashFlowType.PRINCIPAL,
                        related_position=self.symbol
                    )
                )
            
            # 如果有付息，添加利息支付
            if self.coupon_rate > 0:
                # 计算每次付息金额（年化利率除以付息频率）
                
                
                for payment_date in self.payment_dates:
                    if start_date <= payment_date <= end_date:
                        interest_payment = self.accrued_interest(payment_date-timedelta(days=1), 1)
                        cashflows.append(
                            CashFlowData(
                                timestamp=payment_date,
                                asset_type=AssetType.BOND,
                                symbol=self.symbol,
                                amount=interest_payment,
                                cashflow_type=CashFlowType.INTEREST,
                                related_position=self.symbol
                            )
                        )
            
            return sorted(cashflows, key=lambda x: x.timestamp)
    
    def calc_ytm(self, clean_price: float, value_date: datetime) -> float:
        """
        计算到期收益率（YTM）
        使用二分法求解，考虑所有未来现金流的现值
        
        参数:
            clean_price: 净价
            value_date: 计算日期
            
        返回:
            float: 到期收益率（年化）
        """
        def calc_npv(ytm: float) -> float:
            """计算给定收益率下的现金流现值"""
            # 获取从计算日期到到期日的所有现金流
            cashflows = self.get_cashflows(value_date, self.maturity_date)
            
            # 计算所有现金流的现值之和
            total_value = 0
            for cashflow in cashflows:
                cf_date, amount = cashflow.timestamp,cashflow.amount
                # 计算时间间隔（年）
                t = (cf_date - value_date).days / self.interest_basis
                # 计算折现值
                total_value += amount / ((1 + ytm) ** t)
            
            # 返回现值与价格之差
            return total_value - clean_price
            
        # 使用二分法求解YTM
        ytm_low, ytm_high = -0.5, 2.0  # 收益率范围：-50%到200%
        tolerance = 1e-6  # 容差
        max_iter = 100  # 最大迭代次数
        
        # 检查特殊情况
        if clean_price <= 0:
            raise ValueError("价格必须为正数")
            
        # 如果债券已到期，返回0
        if self.is_matured(value_date):
            return 0.0
            
        # 二分法迭代求解
        for _ in range(max_iter):
            ytm_mid = (ytm_low + ytm_high) / 2
            npv = calc_npv(ytm_mid)
            
            # 如果找到解，返回
            if abs(npv) < tolerance:
                return ytm_mid
                
            # 根据npv的符号调整搜索区间
            if npv > 0:
                ytm_low = ytm_mid
            else:
                ytm_high = ytm_mid
                
        # 如果达到最大迭代次数仍未收敛，返回最后的估计值
        return (ytm_low + ytm_high) / 2

    def accrued_interest(self, current_date: datetime, quantity: float) -> float:
        """
        计算应计利息
        考虑付息频率和计息基准的影响
        如果有明确的现金流，则根据明确的付息日期和金额计算
        闰年2月29日当日利息为0，其他日期正常计息
        
        Args:
            current_date: 计算日期
            quantity: 债券数量
            
        Returns:
            float: 应计利息
        """
        # 确保日期是datetime类型
        if isinstance(current_date, int):
            current_date = datetime.fromtimestamp(current_date)
            
        if self.explicit_cashflows is not None:
            if self.is_zero_coupon:
                # 零息债券应该只有一个现金流事件
                if len(self.explicit_cashflows) !=2 and \
                    CashFlowType.PRINCIPAL in [i[2] for i in self.explicit_cashflows] and \
                    CashFlowType.MATURITY in [i[2] for i in self.explicit_cashflows]:
                    raise ValueError(f"零息债券{self.symbol}应该只有两个现金流事件，本金和到期,\
                                        实际收到{len(self.explicit_cashflows)}个")
                principal_payment = \
                        [i for i in self.explicit_cashflows if i[2]==CashFlowType.PRINCIPAL][0][1]
                # 计算计息总天数
                total_days = (self.maturity_date - self.value_date).days
                if total_days <= 0:
                    return 0
                # 计算每日应计利息
                daily_interest = (principal_payment - self.issue_price) / total_days
                # 计算已计息天数
                days_held = (current_date - self.value_date).days
                if days_held < 0:
                    return 0
                    
                # 计算截至当前日期的应计利息
                accrued = daily_interest * days_held
                return quantity * accrued
            else:
                # 找到上一次付息日和付息金额
                last_payment_date = self.value_date
                last_payment_amount = 0
                next_payment_date = None
                next_payment_amount = None
                
                for date, amount, flow_type in self.explicit_cashflows:
                    if flow_type == CashFlowType.INTEREST:
                        if date <= current_date:
                            if date > last_payment_date:
                                last_payment_date = date
                                last_payment_amount = amount
                        else:
                            if next_payment_date is None or date < next_payment_date:
                                next_payment_date = date
                                next_payment_amount = amount

                if next_payment_date is None:
                    return 0
            
                # 计算两个付息日之间的实际天数，算头不算尾
                days_between_payments = (next_payment_date - last_payment_date).days
                # 计算累计利息
                if days_between_payments == 0:
                    logger.info([self.symbol,current_date,next_payment_date,last_payment_date])
                daily_interest = next_payment_amount / days_between_payments
                # 截至当天日终的应计利息
                accrued = daily_interest * ((current_date - last_payment_date).days+1)
                
                return quantity * accrued
        if self.is_zero_coupon:
            
            # 计算计息总天数
            total_days = (self.maturity_date - self.value_date).days
            if total_days <= 0:
                return 0
                
            # 计算每日应计利息
            daily_interest = (self.par_value - self.issue_price) / total_days
            logger.info(daily_interest)
            # 计算已计息天数
            days_held = (current_date - self.value_date).days
            if days_held < 0:
                return 0
                
            # 计算截至当前日期的应计利息
            accrued = daily_interest * days_held
            return quantity * accrued

        else:
            # 普通附息债券
            # 找到上一个付息日
            last_payment_date = self.value_date
            for date in self.payment_dates:
                if date > current_date:
                    break
                last_payment_date = date

            # 计算应计利息（考虑付息频率和计息基准）
            annual_interest = self.par_value * self.coupon_rate
            daily_interest = annual_interest / self.interest_basis 
            # 计算每日利息并累加
            accrued = daily_interest * ((current_date - last_payment_date).days+1)

            return quantity * accrued
    
    def is_matured(self, current_date: datetime) -> bool:
        """判断债券是否到期"""
        return current_date >= self.maturity_date

@dataclass
class Repo(Asset):
    """回购类"""
    principal: float  # 回购本金
    repo_rate: float  # 回购利率
    start_date: datetime = field(default_factory=datetime.now)
    end_date: datetime = field(default_factory=lambda: datetime.now() + timedelta(days=7))
    
    def __post_init__(self):
        self.asset_type = AssetType.REPO
    
    def get_cashflows(self, start_date: datetime, end_date: datetime) -> List[CashFlowData]:
        """获取指定时间段内的现金流事件"""
        cashflows = []
        
        # 确保日期是datetime类型
        if isinstance(start_date, int):
            start_date = datetime.fromtimestamp(start_date)
        if isinstance(end_date, int):
            end_date = datetime.fromtimestamp(end_date)
        
        # 如果回购到期，添加到期事件、本金还款和利息
        if start_date <= self.end_date <= end_date:
            # 到期事件（不涉及实际现金流，仅用于通知）
            cashflows.append(
                CashFlowEvent(
                    type=EventType.CASHFLOW,
                    timestamp=self.end_date,
                    asset_type=AssetType.REPO,
                    symbol=self.symbol,
                    amount=0,
                    cashflow_type=CashFlowType.MATURITY,
                    related_position=self.symbol
                )
            )
            
            # 本金
            cashflows.append(
                CashFlowEvent(
                    type=EventType.CASHFLOW,
                    timestamp=self.end_date,
                    asset_type=AssetType.REPO,
                    symbol=self.symbol,
                    amount=self.principal,
                    cashflow_type=CashFlowType.PRINCIPAL,
                    related_position=self.symbol
                )
            )
            
            # 利息（只在到期时结算）
            days = (self.end_date - self.start_date).days
            interest = self.principal * self.repo_rate * days / 365
            cashflows.append(
                CashFlowEvent(
                    type=EventType.CASHFLOW,
                    timestamp=self.end_date,
                    asset_type=AssetType.REPO,
                    symbol=self.symbol,
                    amount=interest,
                    cashflow_type=CashFlowType.INTEREST,
                    related_position=self.symbol
                )
            )
        
        return cashflows
    
    def is_matured(self, current_date: datetime) -> bool:
        """判断回购是否到期"""
        return current_date >= self.end_date
    
    def accrued_interest(self, current_date: datetime, quantity: float) -> float:
        """计算应计利息"""
        # 确保日期是datetime类型
        if isinstance(current_date, int):
            current_date = datetime.fromtimestamp(current_date)
            
        if current_date < self.end_date:
            days = (current_date - self.start_date).days
            # 使用 quantity 的符号来确定应计利息的方向
            return quantity * self.repo_rate * days / 365
        return 0

@dataclass
class BondFutures(Asset):
    """国债期货类"""
    contract_size: float  # 合约规模
    delivery_date: datetime  # 交割日期
    margin_rate: float = 0.1  # 保证金比例
    
    
    def __post_init__(self):
        self.asset_type = AssetType.FUTURES
        
    
    def get_cashflows(self, start_date: datetime, end_date: datetime) -> List[CashFlowData]:
        """获取指定时间段内的现金流事件"""
        # 期货没有固定的现金流，主要是保证金的缴纳和变动保证金
        return []
    
    def is_matured(self, current_date: datetime) -> bool:
        """判断期货是否到期"""
        return current_date >= self.delivery_date
    
    @property
    def accrued_interest(self, current_date: datetime, quantity: float) -> float:
        """期货没有应计利息"""
        return 0.0